﻿#include "dialognetudp.h"
#include "ui_dialognetudp.h"
#include <QDateTime>
#include <QMessageBox>
#include <QSettings>
#include <QTextStream>
#include <QHostAddress>
#include "tb_interface.h"

static int instance = 0,para_in= 0,para_out = 0;
static QString sendto_addr;

static int sendto_port = 0;
static QString listen_addr;
QHostAddress host_sendto;

static int listen_port = 0;
static bool para_bind = false;
QHostAddress host_listen;

DialogNetUDP::DialogNetUDP(const TASKBUS::cmdlineParser & cmd,QWidget *parent)
	:QDialog(parent)
	,ui(new Ui::DialogNetUDP)
	, m_sock(new QUdpSocket(this))
	,m_pRevThd(new reciv_thread(this))
	,m_cmd(cmd)
{
	ui->setupUi(this);

	instance = cmd.toInt("instance",0);
	para_in = cmd.toInt("input",0);
	para_out = cmd.toInt("output",0);

	sendto_addr = QString::fromStdString(cmd.toString("sendto_addr","127.0.0.1"));
	sendto_port = cmd.toInt("sendto_port",12800);
	host_sendto = QHostAddress(sendto_addr);
	ui->lineEdit_sendAddr->setText(sendto_addr);
	ui->lineEdit_sendPort->setText(QString("%1").arg(sendto_port));


	listen_addr = QString::fromStdString(cmd.toString("listen_addr","0.0.0.0"));
	listen_port = cmd.toInt("listen_port",12800);
	host_listen = QHostAddress(listen_addr);
	ui->lineEdit_listenerAddr->setText(listen_addr);
	ui->lineEdit_listenerPort->setText(QString("%1").arg(listen_port));

	para_bind = cmd.toInt("bind",0)?true:false;
	ui->checkBox_listener_bind->setChecked(para_bind);

	connect(m_pRevThd,&reciv_thread::new_package,this,&DialogNetUDP::slot_new_taskpack,Qt::QueuedConnection);
	connect(m_pRevThd,&reciv_thread::sig_quit,this,&DialogNetUDP::close);
	m_pRevThd->start();
	connect(this,&DialogNetUDP::sig_error,this,&DialogNetUDP::slot_error,Qt::QueuedConnection);

	m_bufdat = (new char [m_bufsize][65536]);
	m_buflen = (new int [m_bufsize]);
	memset(m_buflen,0,sizeof(int)*m_bufsize);

}

DialogNetUDP::~DialogNetUDP()
{
	m_pRevThd->terminate();
	if (m_pBindThread)
	{
		bfinished = true;
		m_pBindThread->join();
		m_pBindThread = nullptr;
	}
	if (m_pWriteThread)
	{
		bfinished = true;
		m_pWriteThread->join();
		m_pWriteThread = nullptr;
	}
	delete ui;
}

void DialogNetUDP::on_pushButton_listerner_start_clicked()
{
	startWork();
}

void DialogNetUDP::startWork()
{
	if(!ui->checkBox_listener_bind->isChecked())
		return;
	if (!m_pBindThread)
	{
		m_pos_write = 0;
		m_pos_read = 0;
		m_pBindThread = new std::thread([this]()->void{

			QUdpSocket sock;
			if (!sock.bind(host_listen,listen_port))
			{
				emit sig_error(sock.errorString());
				return;
			}
			while(!bfinished)
			{
				sock.waitForReadyRead(10);
				while(sock.hasPendingDatagrams())
				{
					long long p = m_pos_write % m_bufsize;
					m_buflen[p] = sock.readDatagram(m_bufdat[p],65536);
					++m_pos_write;
				}
			}
		}
		);
		m_pWriteThread = new std::thread([this]()->void{

			while(!bfinished)
			{
				if (m_pos_read+m_bufsize<m_pos_write)
				{
					m_pos_read = (long long)m_pos_write;
				}
				if(m_pos_read<m_pos_write)
				{
					long long p = m_pos_read % m_bufsize;
					TASKBUS::push_subject(
								para_out,instance,
								m_buflen[p],(const unsigned char *)m_bufdat[p]
								);

					++m_pos_read;
				}
				else
					QThread::msleep(1);
			}
		}
		);
		ui->pushButton_listerner_start->setEnabled(false);
	}
}

void DialogNetUDP::slot_error(QString m)
{
	static QTextStream stmerr(stderr);
	stmerr<< m<<"\n";
	stmerr.flush();
	if (m_pBindThread)
	{
		m_pBindThread->join();
		delete m_pBindThread;
		m_pBindThread = nullptr;
	}
	if (m_pWriteThread)
	{
		bfinished = true;
		m_pWriteThread->join();
		m_pWriteThread = nullptr;
	}
	ui->pushButton_listerner_start->setEnabled(true);
}

void DialogNetUDP::slot_new_taskpack(QByteArray package)
{
	using namespace TASKBUS;
	const subject_package_header * pheader = (const subject_package_header *)
			package.constData();
	const int pts = pheader->data_length;
	const unsigned char * fdata =  (const unsigned char *)(package.constData()+sizeof(subject_package_header));
	if (pts<1)
		return;
	subject_package_header header = *pheader;
	if (m_sock)
	{
		m_sock->writeDatagram((const char *)fdata,header.data_length,host_sendto,sendto_port);
	}
}

void DialogNetUDP::on_lineEdit_sendAddr_textChanged(const QString &arg1)
{
	sendto_addr = arg1;
	host_sendto = QHostAddress(sendto_addr);

}


void DialogNetUDP::on_lineEdit_sendPort_textChanged(const QString &arg1)
{
	sendto_port = arg1.toInt();
}


void DialogNetUDP::on_lineEdit_listenerAddr_textChanged(const QString &arg1)
{
	listen_addr =arg1;
	QHostAddress host_listen;
}


void DialogNetUDP::on_lineEdit_listenerPort_textChanged(const QString &arg1)
{
	listen_port = arg1.toInt();
}


void DialogNetUDP::on_checkBox_listener_bind_toggled(bool checked)
{
	para_bind = checked;
}

